#!/usr/bin/env python
# encoding: utf-8
'''
@author: Excelsiorly
@license: (C) Copyright 2022, All Rights Reserved.
@contact: excelsiorly@qq.com
@file: 072. 编辑距离.py
@time: 2022/1/16 13:20
@desc: https://leetcode-cn.com/problems/edit-distance/
@解题思路：
    给你两个单词 word1 和 word2， 请返回将 word1 转换成 word2 所使用的最少操作数  。
    你可以对一个单词进行如下三种操作：
        - 插入一个字符
        - 删除一个字符
        - 替换一个字符
     
    题解：https://leetcode-cn.com/problems/edit-distance/solution/bian-ji-ju-chi-by-leetcode-solution/
    我们获得 D[i][j-1]，D[i-1][j] 和 D[i-1][j-1] 的值之后就可以计算出 D[i][j]。

        - D[i][j-1] 为 A 的前 i 个字符和 B 的前 j - 1 个字符编辑距离的子问题。即对于 B 的第 j 个字符，我们在 A 的末尾添加了一个相同的字符，
            那么 D[i][j] 最小可以为 D[i][j-1] + 1；

        - D[i-1][j] 为 A 的前 i - 1 个字符和 B 的前 j 个字符编辑距离的子问题。即对于 A 的第 i 个字符，我们在 B 的末尾添加了一个相同的字符，
            那么 D[i][j] 最小可以为 D[i-1][j] + 1；

        - D[i-1][j-1] 为 A 前 i - 1 个字符和 B 的前 j - 1 个字符编辑距离的子问题。即对于 B 的第 j 个字符，我们修改 A 的第 i 个字符使它们相同，
            那么 D[i][j] 最小可以为 D[i-1][j-1] + 1。特别地，如果 A 的第 i 个字符和 B 的第 j 个字符原本就相同，那么我们实际上不需要进行修改操作。
            在这种情况下，D[i][j] 最小可以为 D[i-1][j-1]。

        转移方程为：
            D[i][j] = min(D[i-1][j]+1, D[i][j-1]+1, D[i-1][j-1] + (1 if word1[i]!=word2[j] else 0))

1. Ot(mn), Os(mn)
'''


class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        n, m = len(word1), len(word2)

        # 其中一个为空串
        if n * m == 0: return n + m

        # dp[i][j] 表示word1[1...i]与word2[1...j]字串的编辑距离
        dp = [[0] * (m + 1) for _ in range(n + 1)]

        # 初始化一个非空字串与空字串的情况
        for i in range(n + 1):
            # word1[1...i]与word2空串的编辑距离为i本身（插入i个字符）
            dp[i][0] = i
        for j in range(m + 1):
            dp[0][j] = j

        # dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1], dp[i-1][j-1] + (1 if word1[i-1]!=word2[j-1] else 0))
        for i in range(1, n + 1):
            for j in range(1, m + 1):
                left = dp[i - 1][j] + 1
                right = dp[i][j - 1] + 1
                left_down = dp[i - 1][j - 1] + (1 if word1[i - 1] != word2[j - 1] else 0)
                dp[i][j] = min(left, right, left_down)

        return dp[n][m]